﻿Imports System.IO
Imports System.Diagnostics
Imports System.Threading
Imports System.ComponentModel
Public Class Form1

    ' Threading.Net, is a small windows form application that highlights the benefits of multithreaded programming by comparing in parallel,
    ' using progessbars, the same process running in single thread and in multi thread mode.
    ' This application have been developed by Régis Scyeur

    Private WaitEvents As BitArray
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        GetFiles(Me.TextBox1.Text)
    End Sub

    Public Sub GetFiles(ByVal path As String)
        Button1.Enabled = False
        Dim di As New DirectoryInfo(path)
        Dim files As FileInfo() = di.GetFiles("*.jpg", SearchOption.AllDirectories)
        Dim fileCount As Integer = files.Count

        Dim msg As String = String.Format("{0} have been found", fileCount)
        Label3.Text = msg
        WaitEvents = New BitArray(2, False)

        SingleThreadWorker.RunWorkerAsync(New Object() {files, FileHelperType.SingleThread})
        MultipleThreadWorker.RunWorkerAsync(New Object() {files, FileHelperType.MultiThread})
    End Sub


    Private Sub ThreadWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles SingleThreadWorker.DoWork, MultipleThreadWorker.DoWork
        Dim Worker As BackgroundWorker = CType(sender, BackgroundWorker)
        Dim params() As Object = e.Argument
        Dim files As FileInfo() = CType(params(0), FileInfo())
        Dim mode As FileHelperType = CType(params(1), FileHelperType)
        Dim fp As New FileHelper(files, mode, Worker)
        e.Result = fp.Process()
    End Sub

    Private Sub ThreadWorker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles SingleThreadWorker.ProgressChanged, MultipleThreadWorker.ProgressChanged
        Select Case True
            Case sender.Equals(SingleThreadWorker)
                ProgressBar1.Value = e.ProgressPercentage
                Label1.Text = e.UserState.ToString
            Case sender.Equals(MultipleThreadWorker)
                ProgressBar2.Value = e.ProgressPercentage
                Label2.Text = e.UserState.ToString
        End Select
    End Sub

    Private Sub ThreadWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles SingleThreadWorker.RunWorkerCompleted, MultipleThreadWorker.RunWorkerCompleted
        Beep()
        Beep()
        Select Case True
            Case sender.Equals(SingleThreadWorker)
                Label1.Text = e.Result.ToString
                WaitEvents(0) = True
            Case sender.Equals(MultipleThreadWorker)
                Label2.Text = e.Result.ToString
                WaitEvents(1) = True
        End Select
        If WaitEvents(0) And WaitEvents(1) Then
            Button1.Enabled = True
            MsgBox("Yes ... Multi Threading Is Cool !")
        End If
    End Sub

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        TextBox1.Text = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)
    End Sub
End Class

Public Enum FileHelperType
    SingleThread = 0
    MultiThread = 1
End Enum

Public Class FileHelper
    Private _waitEvent As ManualResetEvent
    Private _files As FileInfo()
    Private _worker As BackgroundWorker

    Public ReadOnly Property FileCount() As Integer
        Get
            Return _files.Count
        End Get
    End Property

    Private _fileProcessedCount As Integer
    Public ReadOnly Property FileProcessedCount() As Integer
        Get
            Dim i As Integer = 0
            Select Case Mode
                Case FileHelperType.SingleThread
                    i = _fileProcessedCount
                Case FileHelperType.MultiThread
                    i = Interlocked.Read(_fileProcessedCount)
            End Select
            Return i
        End Get
    End Property

    Private _mode As FileHelperType
    Public ReadOnly Property Mode() As FileHelperType
        Get
            Return _mode
        End Get
    End Property

    Public Sub New(ByVal files As FileInfo(), ByVal mode As FileHelperType, ByVal worker As BackgroundWorker)
        Me._mode = mode
        Me._files = files
        Me._worker = worker
    End Sub

    Public Function Process() As String
        Dim timer As Stopwatch = Stopwatch.StartNew()
        Select Case Mode
            Case FileHelperType.SingleThread
                ProcessAsSingleThread()
            Case FileHelperType.MultiThread
                ProcessAsMultiThread()
        End Select
        Dim msg As String = String.Format("Mode : {0} - {1} files have been processed in {2}.", Mode.ToString, FileCount, timer.Elapsed.ToString())
        Return msg
    End Function

    Private Sub ProcessAsSingleThread()
        For Each fi As FileInfo In _files
            ProcessFile(fi.FullName)
        Next
    End Sub

    Private Sub ProcessAsMultiThread()
        _waitEvent = New ManualResetEvent(False)
        Dim callBack As New WaitCallback(AddressOf ProcessFile)
        For Each fi As FileInfo In _files
            ThreadPool.QueueUserWorkItem(callBack, fi.FullName)
        Next
        _waitEvent.WaitOne()
    End Sub

    Private Sub ProcessFile(ByVal obj As Object)
        Thread.Sleep(5)
        Dim filename As String = CType(obj, String)
        Dim value As Integer
        Dim percentage As Integer
        Dim msg As String = ""
        Select Case Mode
            Case FileHelperType.SingleThread
                _fileProcessedCount += 1
                value = _fileProcessedCount
            Case FileHelperType.MultiThread
                value = Interlocked.Increment(_fileProcessedCount)
        End Select
        percentage = GetPercentage(value)
        msg = String.Format("Mode : {0} - Thread : {1} - {2}% -File : {3}", Mode.ToString, Thread.CurrentThread.ManagedThreadId, percentage, filename)
        _worker.ReportProgress(percentage, msg)
        If Mode = FileHelperType.MultiThread And value.Equals(Me.FileCount) Then
            _waitEvent.Set()
        End If
    End Sub

    Private Function GetPercentage(ByVal i As Integer) As Integer
        Dim Percentage As Integer = (i / FileCount * 100)
        Return Percentage
    End Function

End Class

